/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package us.levk.remote.drmaa.server.xmlrpc;

import java.util.List;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.ggf.drmaa.DrmaaException;
import org.ggf.drmaa.InvalidJobTemplateException;
import org.ggf.drmaa.JobTemplate;
import org.ggf.drmaa.NoActiveSessionException;
import org.ggf.drmaa.Session;
import org.ggf.drmaa.SessionFactory;

import us.levk.remote.drmaa.common.api.RemoteSession;
import us.levk.remote.drmaa.server.Configuration;


/**
 * @author levk
 *
 */
public class SessionImpl implements RemoteSession {
  private static final long serialVersionUID = 1L;

  private static final transient Logger LOG = Logger.getLogger (SessionImpl.class);

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#init(java.lang.String)
   */
  @Override public UUID init (String contact) throws DrmaaException {
    UUID result = UUID.randomUUID ();
    Session session = SessionFactory.getFactory ().getSession ();
    session.init (contact == null ? Configuration.getConfiguration ().getContact () : contact);
    Instances.SESSIONS.put (result, session);
    LOG.trace ("Initialized session " + result);
    return result;
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#exit(java.util.UUID)
   */
  @Override public void exit (UUID session) throws DrmaaException {
    try { Instances.SESSIONS.get (session).exit (); } catch (NullPointerException e) { throw new NoActiveSessionException (); }
    Instances.SESSIONS.remove (session);
    LOG.trace ("Exited session " + session);
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#createJobTemplate(java.util.UUID)
   */
  @Override public UUID createJobTemplate (UUID session) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    UUID result = UUID.randomUUID ();
    Instances.TEMPLATES.put (result, s.createJobTemplate ());
    LOG.trace ("Created template " + result + " for session " + session);
    return result;
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#deleteJobTemplate(java.util.UUID, java.util.UUID)
   */
  @Override public void deleteJobTemplate (UUID session, UUID template) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    JobTemplate jt = Instances.TEMPLATES.get (template);
    if (jt == null) throw new InvalidJobTemplateException ();
    s.deleteJobTemplate (jt);
    Instances.TEMPLATES.remove (template);
    LOG.trace ("Deleted template " + template + " for session " + session);
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#runJob(java.util.UUID, java.util.UUID)
   */
  @Override public String runJob (UUID session, UUID template) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    JobTemplate jt = Instances.TEMPLATES.get (template);
    if (jt == null) throw new InvalidJobTemplateException ();
    String jobId = s.runJob (jt);
    LOG.trace ("Started job " + jobId + " for template " + template + " for session " + session + " ");
    return jobId;
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#runBulkJobs(java.util.UUID, java.util.UUID, int, int, int)
   */
  @Override public List<?> runBulkJobs (UUID session, UUID template, int start, int end, int incr) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    JobTemplate jt = Instances.TEMPLATES.get (template);
    if (jt == null) throw new InvalidJobTemplateException ();
    List<?> jobs = s.runBulkJobs (jt, start, end, incr);
    LOG.trace ("Started jobs " + jobs + " for template " + template + " for session " + session);
    return jobs;
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#control(java.util.UUID, java.lang.String, int)
   */
  @Override public void control (UUID session, String jobId, int action) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    s.control (jobId, action);
    LOG.trace ("Control action " + action + " for job " + jobId + " for session " + session);
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#synchronize(java.util.UUID, java.util.List, long, boolean)
   */
  @Override public void synchronize (UUID session, List<?> jobIds, long timeout, boolean dispose) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    LOG.trace ("Blocking in synchronize() for session " + session + " on " + jobIds + " for " + timeout); 
    s.synchronize (jobIds, timeout, dispose);
    LOG.trace ("Unblocked in synchronize() for session " + session);
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#wait(java.util.UUID, java.lang.String, long)
   */
  @Override public UUID wait (UUID session, String jobId, long timeout) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    UUID result = UUID.randomUUID ();
    LOG.trace ("Blocking in wait() for session " + session + " on " + jobId + " for " + timeout);
    Instances.INFOS.put (result, s.wait (jobId, timeout));
    LOG.trace ("Unblocked in wait() for session " + session);
    return result;
  }

  /* (non-Javadoc)
   * @see us.levk.remote.drmaa.common.RemoteSession#getJobProgramStatus(java.util.UUID, java.lang.String)
   */
  @Override public int getJobProgramStatus (UUID session, String jobId) throws DrmaaException {
    Session s = Instances.SESSIONS.get (session);
    if (s == null) throw new NoActiveSessionException ();
    int ps = s.getJobProgramStatus (jobId);
    LOG.trace ("Returning job program status " + ps + " for job " + jobId);
    return ps;
  }
}
